import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: wx
 * Date: 2024-03-17
 * Time: 9:36
 */
public class TcpEchoClient {
    private Socket socket = null;
    public TcpEchoClient(String serverIP, int serverPort) throws IOException {
       // 此处可以把这里的 ip 和 port 直接传给 socket 对象
       // 由于 tcp 是有连接的.因此 socket 里面就会保存好这两信息
       // 因此此处 TcpEchoClient 类不必保存
        socket = new Socket(serverIP,serverPort);
    }
    public void start()   {
        System.out.println("客户端启动");
        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()){
            Scanner scannerConsole = new Scanner(System.in);
            Scanner scannerNetwork = new Scanner(inputStream);
            PrintWriter writer = new PrintWriter(outputStream);
            while(true){
                // 这里的流程和 UDP 客户类似
                // 1.从控制台读取输入的字符串
                System.out.print("-> ");
                if (!scannerConsole.hasNext()) {
                    break;
                }

                String request = scannerConsole.next();
                // 2.把请求发给服务器.这里需要用 println 进行发送,为了让发送的请求末尾带有 \n
                // 这里是和服务器 scanner.next 呼应的.
                writer.println(request);
                // 通过 flush 主动刷新缓冲区,确保了数据真的发出去了
                writer.flush();
                // 3.从服务器读取响应,这里和服务器返回响应的逻辑对于
                String response = scannerNetwork.next();
                // 4.把响应显示出来
                System.out.println(response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    public static void main(String[] args) throws IOException {
        TcpEchoClient client = new TcpEchoClient("127.0.0.1",9090);
        client.start();
    }
}

/**
 * 上述代码中需不需要针对client socket 进行close操作?
 *
 * serverSocket 整个程序只有唯一一个对象.并且这个对象的生命周期是要跟随整个程序的.这个对象无法提前关闭.只要程序退出,
 * 随着进程的销毁一起被释放即可.(不需要手动进行)
 *
 * 调用 socket.close 本质上也是关闭文件,释放描述符表.这里进程销毁.文件描述附表当然就没了.因此 DUP
 * 的程序都没有close
 * 但是TCP的 client socket 是每个客户端都有一个.随着客户的增加,这里消耗的socket也越来越多(如果不释放,就可能把文件描述符表给占满了)
 * 这次连接处理完毕(processConnection 结束),就可以 close clientSocket.
 *
 *  try(InputStream inputStream = socket.getInputStream();
 *             OutputStream outputStream = socket.getOutputStream())
 *             这里只是关闭了流对象,而没有释放文件本体
 *             这两流对象都是socket对象给我们创建出来的
 *     释放了 socket 对象,即使上述流对象不释放,也问题不大.这两流对象内部不持有文件描述符表,只是一些内存结构,内存结构可以被gc 释放
 *     但是只是释放流对象,不释放socket 就不行了.socket持有了文件描述符表,本质上还是要释放文件描述符表
 */